# pragma once

# include "cpp_tools_Headers.h"
# include "tinyxml2.h"

namespace cpp_tools
{
    class XmlParameterManager {
    private:
        tinyxml2::XMLDocument doc;
        tinyxml2::XMLElement* root;
        std::string rootName;

    public:
        // 构造函数，创建新文档或从文件加载
        explicit XmlParameterManager(const std::string& rootElementName = "parameters", const std::string& filename = "") 
            : rootName(rootElementName), root(nullptr) 
        {
            if (cpp_tools::checkFile(filename)) 
            {
                loadFromFile(filename);
            } 
            else 
            {
                // 创建新文档
                tinyxml2::XMLDeclaration* declaration = doc.NewDeclaration();
                doc.InsertFirstChild(declaration);
                
                root = doc.NewElement(rootElementName.c_str());
                doc.InsertEndChild(root);
            }
        }

        // 从文件加载XML
        bool loadFromFile(const std::string& filename) 
        {
            tinyxml2::XMLError error = doc.LoadFile(filename.c_str());
            if (error != tinyxml2::XML_SUCCESS) 
            {
                throw std::runtime_error("Failed to load XML file: " + filename + " Error: " + doc.ErrorName());
            }

            root = doc.FirstChildElement(rootName.c_str());
            if (!root) 
            {
                // 如果根元素不存在，创建一个
                root = doc.NewElement(rootName.c_str());
                doc.InsertEndChild(root);
            }
            
            return true;
        }

        // 保存XML到文件
        bool saveToFile(const std::string& filename) 
        {
            if (!root) 
            {
                throw std::runtime_error("XML document is not initialized properly");
            }

            if (!std::filesystem::exists(filename));
            {
                std::filesystem::path dirPath = std::filesystem::path(filename).parent_path();
                
                // 如果目录不存在，则创建目录
                if (!std::filesystem::exists(dirPath)) {
                    if (std::filesystem::create_directories(dirPath)) {
                        // std::cout << "目录创建成功: " << dirPath << std::endl;
                    } else {
                        std::cerr << "目录创建失败: " << dirPath << std::endl;
                        return -1;
                    }
                }
            }

            tinyxml2::XMLError error = doc.SaveFile(filename.c_str());
            if (error != tinyxml2::XML_SUCCESS) 
            {
                throw std::runtime_error("Failed to save XML file: " + filename + " Error: " + doc.ErrorName());
            }
            else
            {
                std::cout << "xml: 数据已成功写入文件：" << filename << std::endl;
            }
            
            return true;
        }

        /// @brief 设置参数
        /// @tparam T 
        /// @param path 节点路径，路径格式："parent/child"
        /// @param name 
        /// @param value 
        /// @return true if succeed
        template<typename T>
        void setParameter(const std::string& path, const std::string& name, const T& value) {
            if (!root) 
            {
                throw std::runtime_error("XML document is not initialized properly");
            }
    
            // 解析路径并创建必要的元素
            tinyxml2::XMLElement* current = root;
            std::vector<std::string> pathElements = splitPath(path);
    
            for (const std::string& elem : pathElements) {
                tinyxml2::XMLElement* child = current->FirstChildElement(elem.c_str());
                if (!child) {
                    child = doc.NewElement(elem.c_str());
                    current->InsertEndChild(child);
                }
                current = child;
            }
    
            // 检查参数是否已存在
            tinyxml2::XMLElement* param = current->FirstChildElement(name.c_str());
            std::stringstream ss;
            ss << value;  // 非浮点数使用默认格式
            
            if (param) {
                // 参数存在，仅更新值
                param->SetText(ss.str().c_str());
            } else {
                // 参数不存在，创建新参数
                param = doc.NewElement(name.c_str());
                param->SetText(ss.str().c_str());
                current->InsertEndChild(param);
            }
        }

        /// @brief 设置参数
        /// @tparam T 
        /// @param path 节点路径，路径格式："parent/child"
        /// @param name 
        /// @param value 
        /// @param precision 精度，保留的小数点个数
        /// @return true if succeed
        template<typename T>
        typename std::enable_if<std::is_floating_point<T>::value>::type
        setParameter(const std::string& path, const std::string& name, const T& value, int precision) {
            if (!root) 
            {
                throw std::runtime_error("XML document is not initialized properly");
            }

            // 解析路径并创建必要的元素
            tinyxml2::XMLElement* current = root;
            std::vector<std::string> pathElements = splitPath(path);

            for (const std::string& elem : pathElements) 
            {
                tinyxml2::XMLElement* child = current->FirstChildElement(elem.c_str());
                if (!child) 
                {
                    child = doc.NewElement(elem.c_str());
                    current->InsertEndChild(child);
                }
                current = child;
            }

            // 检查参数是否已存在
            tinyxml2::XMLElement* param = current->FirstChildElement(name.c_str());
            std::stringstream ss;
            ss.precision(precision);
            ss << std::fixed;  // 固定小数位模式
            ss << value;
            
            if (param) {
                // 参数存在，仅更新值
                param->SetText(ss.str().c_str());
            } else {
                // 参数不存在，创建新参数
                param = doc.NewElement(name.c_str());
                param->SetText(ss.str().c_str());
                current->InsertEndChild(param);
            }
        }

        /// @brief 获取参数
        /// @tparam T 
        /// @param path 节点路径，路径格式："parent/child"
        /// @param name 
        /// @param value 
        /// @return true if succeed
        template<typename T>
        bool getParameter(const std::string& path, const std::string& name, T& value) const 
        {
            if (!root) 
            {
                return false;
            }

            // 解析路径
            tinyxml2::XMLElement* current = root;
            std::vector<std::string> pathElements = splitPath(path);

            for (const std::string& elem : pathElements) 
            {
                current = current->FirstChildElement(elem.c_str());
                if (!current) {
                    return false; // 路径不存在
                }
            }

            // 查找参数
            tinyxml2::XMLElement* param = current->FirstChildElement(name.c_str());
            if (!param) 
            {
                return false; // 参数不存在
            }

            // 尝试转换为目标类型
            const char* text = param->GetText();
            if (!text) 
            {
                return false;
            }

            std::stringstream ss(text);
            ss >> value;
            return !ss.fail();
        }

        // 获取指定路径下的所有子元素名称
        std::vector<std::string> getChildElements(const std::string& path) const 
        {
            std::vector<std::string> result;
            if (!root) 
            {
                return result;
            }

            // 解析路径
            tinyxml2::XMLElement* current = root;
            std::vector<std::string> pathElements = splitPath(path);

            for (const std::string& elem : pathElements) 
            {
                current = current->FirstChildElement(elem.c_str());
                if (!current) 
                {
                    return result; // 路径不存在
                }
            }

            // 收集所有子元素名称
            for (tinyxml2::XMLElement* child = current->FirstChildElement(); child; child = child->NextSiblingElement()) 
            {
                result.push_back(child->Name());
            }

            return result;
        }

        // 获取XML文档的字符串表示
        std::string toString() const 
        {
            tinyxml2::XMLPrinter printer;
            doc.Print(&printer);
            return printer.CStr();
        }

    private:
        // 分割路径字符串为元素列表
        std::vector<std::string> splitPath(const std::string& path) const 
        {
            std::vector<std::string> elements;
            std::string current;

            for (char c : path) 
            {
                if (c == '/') 
                {
                    if (!current.empty()) 
                    {
                        elements.push_back(current);
                        current.clear();
                    }
                } 
                else 
                {
                    current += c;
                }
            }

            if (!current.empty()) 
            {
                elements.push_back(current);
            }

            return elements;
        }
    };
} // namespace xmlparam